using AntMe.Deutsch;
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;

namespace AntMe.Player.BrainArmyAnts
{
    /// <summary>
    /// Diese Datei enthält die Beschreibung für deine Ameise. Die einzelnen Code-Blöcke 
    /// (Beginnend mit "public override void") fassen zusammen, wie deine Ameise in den 
    /// entsprechenden Situationen reagieren soll. Welche Befehle du hier verwenden kannst, 
    /// findest du auf der Befehlsübersicht im Wiki (http://wiki.antme.net/de/API1:Befehlsliste).
    /// 
    /// Wenn du etwas Unterstützung bei der Erstellung einer Ameise brauchst, findest du
    /// in den AntMe!-Lektionen ein paar Schritt-für-Schritt Anleitungen.
    /// (http://wiki.antme.net/de/Lektionen)
    /// </summary>
    [Spieler(
        Volkname = "BrainArmyAnts",   // Hier kannst du den Namen des Volkes festlegen
        Vorname = "Sebastian",       // An dieser Stelle kannst du dich als Schöpfer der Ameise eintragen
        Nachname = "Seedorf"       // An dieser Stelle kannst du dich als Schöpfer der Ameise eintragen
    )]

    /// Kasten stellen "Berufsgruppen" innerhalb deines Ameisenvolkes dar. Du kannst hier mit
    /// den Fähigkeiten einzelner Ameisen arbeiten. Wie genau das funktioniert kannst du der 
    /// Lektion zur Spezialisierung von Ameisen entnehmen (http://wiki.antme.net/de/Lektion7).
    [Kaste(
        Name = "Sammler",                  // Name der Berufsgruppe
        AngriffModifikator = -1,             // Angriffsstärke einer Ameise
        DrehgeschwindigkeitModifikator = -1, // Drehgeschwindigkeit einer Ameise
        EnergieModifikator = -1,             // Lebensenergie einer Ameise
        GeschwindigkeitModifikator = 2,     // Laufgeschwindigkeit einer Ameise
        LastModifikator = 2,                // Tragkraft einer Ameise
        ReichweiteModifikator = -1,          // Ausdauer einer Ameise
        SichtweiteModifikator = 0           // Sichtweite einer Ameise
    ),
     Kaste(
         Name = "Erkunder",                  // Name der Berufsgruppe
         AngriffModifikator = -1,             // Angriffsstärke einer Ameise
         DrehgeschwindigkeitModifikator = -1, // Drehgeschwindigkeit einer Ameise
         EnergieModifikator = -1,             // Lebensenergie einer Ameise
         GeschwindigkeitModifikator = 1,     // Laufgeschwindigkeit einer Ameise
         LastModifikator = -1,                // Tragkraft einer Ameise
         ReichweiteModifikator = 1,          // Ausdauer einer Ameise
         SichtweiteModifikator = 2           // Sichtweite einer Ameise
     ),
     Kaste(
         Name = "Krieger",                  // Name der Berufsgruppe
         AngriffModifikator = 2,             // Angriffsstärke einer Ameise
         DrehgeschwindigkeitModifikator = 1, // Drehgeschwindigkeit einer Ameise
         EnergieModifikator = 1,             // Lebensenergie einer Ameise
         GeschwindigkeitModifikator = -1,     // Laufgeschwindigkeit einer Ameise
         LastModifikator = -1,                // Tragkraft einer Ameise
         ReichweiteModifikator = -1,          // Ausdauer einer Ameise
         SichtweiteModifikator = -1           // Sichtweite einer Ameise
     )]

    public class BrainArmyAntsKlasse : Basisameise
    {
        private static Bau bau = null;
        private static readonly Random rand = new Random();
        private static readonly List<Zucker> VorkZuckers = new List<Zucker>();
        private static readonly List<int> RemovedZuckers = new List<int>();
        private static readonly List<ObstTraeger> VorkObsts = new List<ObstTraeger>();
        
        private Spielobjekt _z;
        
        #region Kasten

        /// <summary>
        /// Jedes mal, wenn eine neue Ameise geboren wird, muss ihre Berufsgruppe
        /// bestimmt werden. Das kannst du mit Hilfe dieses Rückgabewertes dieser 
        /// Methode steuern.
        /// Weitere Infos unter http://wiki.antme.net/de/API1:BestimmeKaste
        /// </summary>
        /// <param name="anzahl">Anzahl Ameisen pro Kaste</param>
        /// <returns>Name der Kaste zu der die geborene Ameise gehören soll</returns>
        public override string BestimmeKaste(Dictionary<string, int> anzahl)
        {
            int count = 0;
            foreach(KeyValuePair<string, int> entry in anzahl)
            {
                count += entry.Value;
            }
            if (anzahl["Sammler"] > anzahl["Erkunder"] * 12)
                return "Erkunder";


            // Gibt den Namen der betroffenen Kaste zurück.
            return "Sammler";
        }

        #endregion

        #region Fortbewegung

        /// <summary>
        /// Wenn die Ameise keinerlei Aufträge hat, wartet sie auf neue Aufgaben. Um dir das 
        /// mitzuteilen, wird diese Methode hier aufgerufen.
        /// Weitere Infos unter http://wiki.antme.net/de/API1:Wartet
        /// </summary>
        public override void Wartet()
        {
            //GeheGeradeaus();
            //SprüheMarkierung(5, 100);
        }

        /// <summary>
        /// Erreicht eine Ameise ein drittel ihrer Laufreichweite, wird diese Methode aufgerufen.
        /// Weitere Infos unter http://wiki.antme.net/de/API1:WirdM%C3%BCde
        /// </summary>
        public override void WirdMüde()
        {
            //GeheZuBau();
        }

        /// <summary>
        /// Wenn eine Ameise stirbt, wird diese Methode aufgerufen. Man erfährt dadurch, wie 
        /// die Ameise gestorben ist. Die Ameise kann zu diesem Zeitpunkt aber keinerlei Aktion 
        /// mehr ausführen.
        /// Weitere Infos unter http://wiki.antme.net/de/API1:IstGestorben
        /// </summary>
        /// <param name="todesart">Art des Todes</param>
        public override void IstGestorben(Todesart todesart)
        {
            foreach (ObstTraeger obstTraeger in VorkObsts)
            {
                obstTraeger.AmeiseEntfernen(this);
            }
        }

        /// <summary>
        /// Diese Methode wird in jeder Simulationsrunde aufgerufen - ungeachtet von zusätzlichen 
        /// Bedingungen. Dies eignet sich für Aktionen, die unter Bedingungen ausgeführt werden 
        /// sollen, die von den anderen Methoden nicht behandelt werden.
        /// Weitere Infos unter http://wiki.antme.net/de/API1:Tick
        /// </summary>
        public override void Tick()
        {
            if (IstMüde)
            {
                SchrittBau();
                return;
            }



            if (Kaste == "Sammler")
            {
                if (GetragenesObst != null && AnzahlAmeisenDerSelbenKasteInSichtweite < 10)
                    SprüheMarkierung(2, 250);


                if (AktuelleLast > 0)
                {
                    SprüheMarkierung(5, 30);
                    SchrittBau();
                }
                else
                {
                    _z = BestimmeZiel();
                    if (_z == null)
                    {
                        GeheGeradeaus(10);
                        if (rand.Next(50) == 0)
                            DreheUmWinkel(60);
                    }
                    else
                    {
                        SchrittZiel(_z);
                    }
                }
            }
            else
            {
                GeheGeradeaus();
                SprüheMarkierung(4, 30);
            }


        }

        #endregion

        #region Nahrung

        /// <summary>
        /// Sobald eine Ameise innerhalb ihres Sichtradius einen Apfel erspäht wird 
        /// diese Methode aufgerufen. Als Parameter kommt das betroffene Stück Obst.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:Sieht(Obst)"
        /// </summary>
        /// <param name="obst">Das gesichtete Stück Obst</param>
        public override void Sieht(Obst obst)
        {
            /*if (Ziel == null && BrauchtNochTräger(obst))
                SchrittZiel(obst);*/
            ObstHinzufügen(obst);
        }

        /// <summary>
        /// Sobald eine Ameise innerhalb ihres Sichtradius einen Zuckerhügel erspäht wird 
        /// diese Methode aufgerufen. Als Parameter kommt der betroffene Zuckerghügel.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:Sieht(Zucker)"
        /// </summary>
        /// <param name="zucker">Der gesichtete Zuckerhügel</param>
        public override void Sieht(Zucker zucker)
        {
            ZuckerHinzufügen(zucker);
            ZuckerEntfernen(); /////////////////////////////////////////////////////
        }

        /// <summary>
        /// Hat die Ameise ein Stück Obst als Ziel festgelegt, wird diese Methode aufgerufen, 
        /// sobald die Ameise ihr Ziel erreicht hat. Ab jetzt ist die Ameise nahe genug um mit 
        /// dem Ziel zu interagieren.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:ZielErreicht(Obst)"
        /// </summary>
        /// <param name="obst">Das erreichte Stück Obst</param>
        public override void ZielErreicht(Obst obst)
        {
            if (Kaste == "Sammler")
            {
                Nimm(obst);
            }
        }

        /// <summary>
        /// Hat die Ameise eine Zuckerhügel als Ziel festgelegt, wird diese Methode aufgerufen, 
        /// sobald die Ameise ihr Ziel erreicht hat. Ab jetzt ist die Ameise nahe genug um mit 
        /// dem Ziel zu interagieren.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:ZielErreicht(Zucker)"
        /// </summary>
        /// <param name="zucker">Der erreichte Zuckerhügel</param>
        public override void ZielErreicht(Zucker zucker)
        {
            if (Kaste == "Sammler")
            {
                Nimm(zucker);
                ZuckerEntfernen();
            }
        }

        #endregion

        #region Kommunikation

        /// <summary>
        /// Markierungen, die von anderen Ameisen platziert werden, können von befreundeten Ameisen 
        /// gewittert werden. Diese Methode wird aufgerufen, wenn eine Ameise zum ersten Mal eine 
        /// befreundete Markierung riecht.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:RiechtFreund(Markierung)"
        /// </summary>
        /// <param name="markierung">Die gerochene Markierung</param>
        public override void RiechtFreund(Markierung markierung)
        {
            /*if ((markierung.Information & 255) == 2 && Ziel == null) // Apfel
                SchrittZiel(markierung);*/
        }

        /// <summary>
        /// So wie Ameisen unterschiedliche Nahrungsmittel erspähen können, entdecken Sie auch 
        /// andere Spielelemente. Entdeckt die Ameise eine Ameise aus dem eigenen Volk, so 
        /// wird diese Methode aufgerufen.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:SiehtFreund(Ameise)"
        /// </summary>
        /// <param name="ameise">Erspähte befreundete Ameise</param>
        public override void SiehtFreund(Ameise ameise)
        {

        }

        /// <summary>
        /// So wie Ameisen unterschiedliche Nahrungsmittel erspähen können, entdecken Sie auch 
        /// andere Spielelemente. Entdeckt die Ameise eine Ameise aus einem befreundeten Volk 
        /// (Völker im selben Team), so wird diese Methode aufgerufen.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:SiehtVerb%C3%BCndeten(Ameise)"
        /// </summary>
        /// <param name="ameise">Erspähte verbündete Ameise</param>
        public override void SiehtVerbündeten(Ameise ameise)
        {
        }

        #endregion

        #region Kampf

        /// <summary>
        /// So wie Ameisen unterschiedliche Nahrungsmittel erspähen können, entdecken Sie auch 
        /// andere Spielelemente. Entdeckt die Ameise eine Ameise aus einem feindlichen Volk, 
        /// so wird diese Methode aufgerufen.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:SiehtFeind(Ameise)"
        /// </summary>
        /// <param name="ameise">Erspähte feindliche Ameise</param>
        public override void SiehtFeind(Ameise ameise)
        {
        }

        /// <summary>
        /// So wie Ameisen unterschiedliche Nahrungsmittel erspähen können, entdecken Sie auch 
        /// andere Spielelemente. Entdeckt die Ameise eine Wanze, so wird diese Methode aufgerufen.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:SiehtFeind(Wanze)"
        /// </summary>
        /// <param name="wanze">Erspähte Wanze</param>
        public override void SiehtFeind(Wanze wanze)
        {
        }

        /// <summary>
        /// Es kann vorkommen, dass feindliche Lebewesen eine Ameise aktiv angreifen. Sollte 
        /// eine feindliche Ameise angreifen, wird diese Methode hier aufgerufen und die 
        /// Ameise kann entscheiden, wie sie darauf reagieren möchte.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:WirdAngegriffen(Ameise)"
        /// </summary>
        /// <param name="ameise">Angreifende Ameise</param>
        public override void WirdAngegriffen(Ameise ameise)
        {
        }

        /// <summary>
        /// Es kann vorkommen, dass feindliche Lebewesen eine Ameise aktiv angreifen. Sollte 
        /// eine Wanze angreifen, wird diese Methode hier aufgerufen und die Ameise kann 
        /// entscheiden, wie sie darauf reagieren möchte.
        /// Weitere Infos unter "http://wiki.antme.net/de/API1:WirdAngegriffen(Wanze)"
        /// </summary>
        /// <param name="wanze">Angreifende Wanze</param>
        public override void WirdAngegriffen(Wanze wanze)
        {
        }


        #endregion

        #region Eigene

        private Spielobjekt BestimmeZiel()
        {
            ZuckerEntfernen();
            ObstEntfernen();
            var entfernung = int.MaxValue;
            
            
            Spielobjekt s = null;
            foreach (ObstTraeger obstTraeger in VorkObsts)
            {
                if (obstTraeger.IstTraeger(this)) return obstTraeger.Obst;
            }
            foreach (var obst in VorkObsts)
            {
                var neu = Koordinate.BestimmeEntfernung(this, obst.Obst);
                if (s != null && neu >= entfernung || neu >= Reichweite / 3 || !obst.BrauchtNochTraeger()) continue; //Ich verstehe das "z != null &&" nicht
                s = obst.Obst;
                entfernung = neu;
            }
            
            foreach (var zucker in VorkZuckers)
            {
                var neu = Koordinate.BestimmeEntfernung(this, zucker);
                if (s != null && neu >= entfernung || neu >= Reichweite / 3) continue; //Ich verstehe das "z != null &&" nicht
                s = zucker;
                entfernung = neu;
            }

            if (s is Obst)
            {
                VorkObsts.Find(o => o.Obst == s).AmeiseHinzufügen(this);
            }
            return s;

        }

        private void SchrittZiel(Spielobjekt ziel)
        {
            var dist = Koordinate.BestimmeEntfernung(this, ziel);
            var angle = Koordinate.BestimmeRichtung(this, ziel);
            if (Math.Abs(angle-Richtung) > 10)
                DreheInRichtung(angle);
            DreheZuZiel(ziel);
            if (dist > 2)
                GeheGeradeaus(dist/3*2);
            else
                GeheZuZiel(ziel);
        }

        private void SchrittBau()
        {
            if (bau == null)
            {
                GeheZuBau();
                bau = (Bau) Ziel;
                BleibStehen();
            }
            var dist = Koordinate.BestimmeEntfernung(this, bau);
            var angle = Koordinate.BestimmeRichtung(this, bau);
            if (Math.Abs(angle-Richtung) > 10)
                DreheInRichtung(angle);
            if (dist > 4)
                GeheGeradeaus(dist-2);
            else
                GeheZuZiel(bau);
        }

        private static void ZuckerHinzufügen(Zucker zucker)
        {
            if (zucker.Menge > 100 && !VorkZuckers.Contains(zucker) && RemovedZuckers.All(z => z != zucker.Id))
            {
                VorkZuckers.Add(zucker);
            }
        }

        private static void ObstHinzufügen(Obst obst)
        {
            if (VorkObsts.All(o => o.Obst != obst))
            {
                VorkObsts.Add(new ObstTraeger(obst));
            }
        }

        private static void ZuckerEntfernen()//Zucker zucker
        {
            for (int i = 0; i < VorkZuckers.Count; )
            {
                var zucker = VorkZuckers[i];
                if (zucker.Menge > 0)
                {
                    i++;
                }
                else
                {
                    if (VorkZuckers.Contains(zucker))
                    {
                        VorkZuckers.Remove(zucker);
                    }
                    if (!RemovedZuckers.Contains(zucker.Id))
                    {
                        RemovedZuckers.Add(zucker.Id);
                    }
                }
            }
        }

        private static void ObstEntfernen()
        {
            for (int i = 0; i < VorkObsts.Count; )
            {
                var obst = VorkObsts[i];
                if (obst.Obst.Menge > 0)
                {
                    i++;
                }
                else
                {
                    VorkObsts.Remove(obst);
                }
            }
        }


        #endregion

    }

    public class ObstTraeger
    {
        public Obst Obst;
        private readonly List<BrainArmyAntsKlasse> ameisen;

        public ObstTraeger(Obst obst)
        {
            Obst = obst;
            ameisen = new List<BrainArmyAntsKlasse>();
        }

        public bool BrauchtNochTraeger()
        {
            return ameisen.Count < 10;
        }

        public void AmeiseHinzufügen(BrainArmyAntsKlasse ameise)
        {
            ameisen.Add(ameise);
        }

        public void AmeiseEntfernen(BrainArmyAntsKlasse ameise)
        {
            ameisen.Remove(ameise);
        }

        public bool IstTraeger(BrainArmyAntsKlasse ameise)
        {
            return ameisen.Contains(ameise);
        }
     
    }


}
